package com.suray.basic.wcs.plc.utils;

import com.suray.basic.wcs.plc.core.Plc;
import com.suray.basic.wcs.plc.enums.CargoState;
import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.enums.Network;
import com.suray.basic.wcs.plc.enums.PlcDeviceType;
import com.suray.basic.wcs.plc.pojo.DeviceBase;
import com.suray.basic.wcs.plc.pojo.oper.lifter.LifterOper;
import com.suray.basic.wcs.plc.pojo.oper.StationOper;
import com.suray.basic.wcs.plc.pojo.oper.lifter.TwoDirectionRgvLifterOper;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.LoggerUtil;

import java.io.IOException;

public class PlcUnit {
    private static int incrementNum = 3;// PLC的任务号

    /**
     * 判断提升机内部设备是否可取状态 true 为可取
     *
     * @param coord
     * @return
     * @throws PlcExecuteException
     */
    public static boolean isLifterCanGet(Coord coord) throws PlcExecuteException {
        LifterOper lifterOper = PlcUnit.getLifterOper(coord);
        if (baseCheck(lifterOper)) return false;
        return lifterOper.isPalletExisted(1, lifterOper.getLocation()) && !lifterOper.isFacilityExisted(coord.getZ(), lifterOper.getLocation()) && !lifterOper.disconnect();
    }

    /**
     * 读取PLC信息前基础信息校验
     *
     * @param deviceBase
     * @return
     */
    private static boolean baseCheck(DeviceBase deviceBase) {
        if (deviceBase.getPlc().getPlcStatus() == Network.OFF_LINE) {
            LoggerUtil.info(deviceBase.getDeviceName() + "离线，不能取货", deviceBase.getClass());
            return true;
        }
        if (deviceBase.getPlc().getPlcCache().isTimeOut()) {
            LoggerUtil.info(deviceBase.getDeviceName() + "plc缓存数据已超时，不能取货", deviceBase.getClass());
            return true;
        }
        return false;
    }

    /**
     * 判断工位设备是否可取状态 true 为可取
     * 有货&未运行&有任务为可取
     *
     * @param coord
     * @return
     * @throws PlcExecuteException
     */
    public static boolean isCanGet(Coord coord) throws PlcExecuteException {
        DeviceBase deviceBase = Plc.deviceStationCoordMap.get(coord);
        if (deviceBase != null) {
            if (baseCheck(deviceBase)) return false;
            StationOper stationOper = (StationOper) deviceBase;
            return stationOper.isCanGet() && !stationOper.isRunIng();
        } else {
            deviceBase = PlcUnit.getLifterOper(coord);
            if (deviceBase == null) {
                throw new PlcExecuteException("此坐标" + coord.toString() + "无对应设备！请检查配置");
            } else {
                if (baseCheck(deviceBase)) return false;
                LifterOper lifterOper = (LifterOper) deviceBase;
                return lifterOper.isPalletExisted(coord.getZ(), lifterOper.getLocation()) && !lifterOper.isFacilityExisted(coord.getZ(), lifterOper.getLocation()) && !lifterOper.disconnect();
            }
        }
    }

    /**
     * 判断工位设备是否可放状态 true 为可放
     * 无货&未运行&无任务为可放
     *
     * @param coord
     * @return
     * @throws PlcExecuteException
     */
    public static boolean isCanPut(Coord coord) throws PlcExecuteException {
        DeviceBase deviceBase = Plc.deviceStationCoordMap.get(coord);
        if (deviceBase != null) {
            if (baseCheck(deviceBase)) return false;
            StationOper stationOper = (StationOper) deviceBase;
            return stationOper.isCanPut() && !stationOper.isRunIng();
        } else {
            deviceBase = PlcUnit.getLifterOper(coord);
            if (deviceBase == null) {
                throw new PlcExecuteException("此坐标" + coord.toString() + "无对应设备！请检查配置");
            } else {
                if (baseCheck(deviceBase)) return false;
                LifterOper lifterOper = (LifterOper) deviceBase;
                return !lifterOper.isPalletExisted(coord.getZ(), lifterOper.getLocation()) && !lifterOper.isFacilityExisted(coord.getZ(), lifterOper.getLocation()) && !lifterOper.disconnect();
            }
        }
    }

    /**
     * 通过坐标获取到提升机操作对象
     * 默认z轴为1
     *
     * @param coord 坐标
     * @return 提升机操作对象
     */
    public static LifterOper getLifterOper(Coord coord) {
        LifterOper lifterOper = (LifterOper) Plc.deviceLifterCoordMap.get(new Coord(coord.getX(), coord.getY(), 1));
        /*if (lifterOper == null) {
            throw new RuntimeException("该节点无法获取到提升机操作对象" + coord);
        }*/
        return lifterOper;
    }

    /**
     * 判断工位设备是否有货 true 为有货
     * 有货
     *
     * @param coord
     * @return
     * @throws PlcExecuteException
     */
    public static boolean isHaveCargo(Coord coord) throws PlcExecuteException {
        DeviceBase deviceBase = Plc.deviceStationCoordMap.get(coord);
        if (deviceBase != null) {
            if (baseCheck(deviceBase)) return false;
            return ((StationOper) deviceBase).isPalletExist();
        } else {
            deviceBase = PlcUnit.getLifterOper(coord);
            if (deviceBase == null) {
                throw new PlcExecuteException("此坐标" + coord.toString() + "无对应设备！请检查配置");
            } else {
                if (baseCheck(deviceBase)) return false;
                LifterOper lifterOper = (LifterOper) deviceBase;
                return lifterOper.isPalletExisted(coord.getZ(), lifterOper.getLocation());
            }
        }
    }

    /**
     * 获取指令序号
     */
    public static synchronized int getAutoIncrementNum() {
        return incrementNum == 5000 ? incrementNum = 2000 : incrementNum++;
    }

    /**
     * 判断该点属于提升机左点还是右点
     *
     * @param
     * @return
     */
    public static Location judgeLeftOrRightNode(Coord coord) {
        DeviceBase pb = Plc.deviceLifterCoordMap.get(new Coord(coord.getX(), coord.getY(), 1));
        if (pb == null) {
            throw new RuntimeException("提升机没有对应得的设备位置");
        }
        return Location.parseLocationCode(pb.getLocation().getCode());
    }

    /**
     * 写自卸式提升机货位状态/有货或无货
     */
    public static void writeTwoDirectionRgvCargoState(Coord coord, CargoState cargoState) throws IOException {
        LifterOper lifterOper = getLifterOper(coord);
        writeTwoDirectionRgvCargoState(lifterOper, judgeLeftOrRightNode(coord), coord.getZ(), cargoState);
    }


    /**
     * 写自卸式提升机货位状态/有货或无货
     */
    public static void writeTwoDirectionRgvCargoState(LifterOper lifterOper, Location location, Integer floor, CargoState cargoState) throws IOException {
        if (lifterOper instanceof TwoDirectionRgvLifterOper) {
            TwoDirectionRgvLifterOper twoDirectionRgvLifterOper = (TwoDirectionRgvLifterOper) lifterOper;
            if (!twoDirectionRgvLifterOper.readCargoState()) {
                LoggerUtil.error("写入提升机-->" + lifterOper.getDeviceName() + "位置-->" + floor +
                        "失败:" + location.toString(), PlcUnit.class);
                throw new RuntimeException("提升机货位状态错误,不能写入-->" + floor + location.getDescription());
            }
            twoDirectionRgvLifterOper.writeCargoState(floor, location, cargoState);
            LoggerUtil.info("写入提升机-->" + lifterOper.getDeviceName() + "位置-->" + floor +
                    ":" + location.toString(), PlcUnit.class);
        }
    }

    public static LifterOper getAutomaticLifterOper(Coord coord) {
        LifterOper lifterOper = (LifterOper) Plc.deviceLifterCoordMap.get(new Coord(coord.getX(), coord.getY(), 1));
        if (lifterOper != null && lifterOper.getPlcDeviceType() != PlcDeviceType.AUTOMATIC_LIFTER) {
            return null;
        }
        return lifterOper;
    }
}
